package org.jeecg.modules.gather.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.gather.component.DetailsPageSpider;
import org.jeecg.modules.gather.mapper.WebCaptureMapper;
import org.jeecg.modules.gather.model.entity.WebCaptureEntity;
import org.jeecg.modules.gather.model.entity.WebCaptureSaveEntity;
import org.jeecg.modules.gather.model.query.WebCaptureQuery;
import org.jeecg.modules.gather.seaweedfs.SeaweedFSProperties;
import org.jeecg.modules.gather.seaweedfs.SeaweedFSUtil;
import org.jeecg.modules.gather.service.WebCaptureSaveService;
import org.jeecg.modules.gather.service.WebCaptureService;
import org.jeecg.modules.gather.wkhtmltopdf.WkHtmlToPdfUtil;
import org.jeecg.modules.strategy.mapper.WebsiteMetaMapper;
import org.jeecg.modules.strategy.model.entity.MetaEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@EnableConfigurationProperties(SeaweedFSProperties.class)
public class WebCaptureServiceImpl extends ServiceImpl<WebCaptureMapper, WebCaptureEntity> implements WebCaptureService {
    private final DetailsPageSpider detailsPageSpider;
    private final WebsiteMetaMapper websiteMetaMapper;
    private final SeaweedFSProperties seaweedFSProperties;
    private final SeaweedFSUtil seaweedFSUtil;
    private final WebCaptureSaveService webCaptureSaveService;

    @Autowired
    public WebCaptureServiceImpl(DetailsPageSpider detailsPageSpider,
                                 WebsiteMetaMapper websiteMetaMapper,
                                 SeaweedFSProperties seaweedFSProperties,
                                 SeaweedFSUtil seaweedFSUtil,
                                 WebCaptureSaveService webCaptureSaveService) {
        this.detailsPageSpider = detailsPageSpider;
        this.websiteMetaMapper = websiteMetaMapper;
        this.seaweedFSProperties = seaweedFSProperties;
        this.seaweedFSUtil = seaweedFSUtil;
        this.webCaptureSaveService = webCaptureSaveService;
    }

    @Override
    public Result<String> startWebCaptureTask(WebCaptureQuery webCaptureQuery) {
        LambdaQueryWrapper<WebCaptureEntity> webCaptureEntityWrapper = Wrappers.lambdaQuery();
        webCaptureEntityWrapper.eq(WebCaptureEntity::getSiteDomain, webCaptureQuery.getSiteDomain())
                .eq(WebCaptureEntity::getSiteName, webCaptureQuery.getSiteName())
                .eq(WebCaptureEntity::getSiteIdCode, webCaptureQuery.getSiteIdCode())
                .eq(WebCaptureEntity::getColumnName, webCaptureQuery.getColumnName())
                .eq(WebCaptureEntity::getIsDelete, "0");
        List<WebCaptureEntity> webCaptureEntityList = this.getBaseMapper().selectList(webCaptureEntityWrapper);
        if (!webCaptureEntityList.isEmpty())
            return Result.error("该网站已存在采集任务");

        WebCaptureEntity webCaptureEntitySave = new WebCaptureEntity();
        BeanUtil.copyProperties(webCaptureQuery, webCaptureEntitySave);
        webCaptureEntitySave.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        webCaptureEntitySave.setStatus(0);
        String thisTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        webCaptureEntitySave.setCreateTime(thisTime);
        webCaptureEntitySave.setUpdateTime(thisTime);
        webCaptureEntitySave.setIsDelete(0);
        boolean save = this.save(webCaptureEntitySave);
        if (!save)
            return Result.error("采集任务保存失败");

        LambdaQueryWrapper<MetaEntity> metaEntityWrapper = Wrappers.lambdaQuery();
        metaEntityWrapper.eq(MetaEntity::getSiteDomain, webCaptureQuery.getSiteDomain())
                .eq(MetaEntity::getSiteName, webCaptureQuery.getSiteName())
                .eq(MetaEntity::getSiteIdCode, webCaptureQuery.getSiteIdCode())
                .eq(MetaEntity::getColumnName, webCaptureQuery.getColumnName())
                .ne(MetaEntity::getArticleTitle, "")
                .isNotNull(MetaEntity::getArticleTitle)
                .eq(MetaEntity::getIsDelete, "0");
        List<MetaEntity> metaEntityList = websiteMetaMapper.selectList(metaEntityWrapper);
        if (metaEntityList.isEmpty()) {
            this.removeById(webCaptureEntitySave.getId());
            return Result.error("该栏目暂无采集任务");
        }

        captureAndSave(metaEntityList);

        LambdaQueryWrapper<WebCaptureSaveEntity> WebCaptureSaveWrapper = Wrappers.lambdaQuery();
        WebCaptureSaveWrapper.eq(WebCaptureSaveEntity::getSiteDomain, webCaptureEntitySave.getSiteDomain())
                .eq(WebCaptureSaveEntity::getSiteName, webCaptureEntitySave.getSiteName())
                .eq(WebCaptureSaveEntity::getSiteIdCode, webCaptureEntitySave.getSiteIdCode())
                .eq(WebCaptureSaveEntity::getColumnName, webCaptureEntitySave.getColumnName())
                .eq(WebCaptureSaveEntity::getIsDelete, "0");
        long WebCaptureSaveTotal = webCaptureSaveService.count(WebCaptureSaveWrapper);

        WebCaptureEntity webCaptureEntityUpdate = new WebCaptureEntity();
        BeanUtil.copyProperties(webCaptureEntitySave, webCaptureEntityUpdate);
        webCaptureEntityUpdate.setTotal((int) WebCaptureSaveTotal);
        webCaptureEntityUpdate.setStatus(1);
        webCaptureEntityUpdate.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        boolean update = this.updateById(webCaptureEntityUpdate);

        Path folderPath = Paths.get(seaweedFSProperties.getTemporarilyPath());
        deletePdfFiles(folderPath);

        if (update)
            return Result.OK("采集任务已完成");
        else
            return Result.error("采集任务保存失败");
    }

    private void captureAndSave(List<MetaEntity> metaEntityList) {
        for (MetaEntity metaEntity : metaEntityList) {
            String url = metaEntity.getUrl();
            String[] splitUrl = url.split("/");
            String fileName = splitUrl[splitUrl.length - 1];
            String fileExtension = FilenameUtils.getExtension(url).toLowerCase();
            String replaceFileName = fileName.replace("." + fileExtension, "");
            String newFileName = replaceFileName + "." + fileExtension;
            String htmlFilePath = seaweedFSProperties.getUrl() + "/" + seaweedFSProperties.getWebPath() + "/" + newFileName;
            String[] splitFileName = fileName.split("\\.");
            String pdfFilePath = seaweedFSProperties.getTemporarilyPath() + splitFileName[0] + ".pdf";
            String pdfFilePathServe = seaweedFSProperties.getUrl() + "/" + seaweedFSProperties.getHtmlToPdfPath() + "/" + splitFileName[0] + ".pdf";

            String detailsPageContent = detailsPageSpider.startDetailsPageTask(url);
            if (detailsPageContent.equals("error"))
                log.error("采集任务失败");

            boolean htmlFileExists = seaweedFSUtil.isFileExists(htmlFilePath);
            boolean pdfFileExists = seaweedFSUtil.isFileExists(pdfFilePathServe);
            if (htmlFileExists && !pdfFileExists) {
                htmlToPdf(htmlFilePath, pdfFilePath, pdfFilePathServe, splitFileName);

                WebCaptureSaveEntity webCaptureSaveEntity = new WebCaptureSaveEntity();
                BeanUtil.copyProperties(metaEntity, webCaptureSaveEntity);
                String thisTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                webCaptureSaveEntity.setId(UUID.randomUUID().toString().replaceAll("-", ""));
                webCaptureSaveEntity.setPdfUrl(pdfFilePathServe);
                webCaptureSaveEntity.setHtmlUrl(htmlFilePath);
                webCaptureSaveEntity.setCreateTime(thisTime);
                webCaptureSaveEntity.setUpdateTime(thisTime);
                webCaptureSaveEntity.setIsDelete(0);
                webCaptureSaveService.save(webCaptureSaveEntity);
            }
        }
    }

    private void htmlToPdf(String htmlFilePath, String pdfFilePath, String pdfFilePathServe, String[] splitFileName) {
        try {
            Path path = Paths.get(seaweedFSProperties.getTemporarilyPath());
            if (!Files.exists(path)) {
                Files.createDirectories(path);
                log.info("目录创建成功: {}", path);
            }
        } catch (IOException e) {
            log.error("目录创建失败: {}", e.getMessage());
        }
        boolean convert = WkHtmlToPdfUtil.convert(htmlFilePath, pdfFilePath);
        if (!convert) {
            File file = new File(pdfFilePath);
            if (file.exists()) {
                Map<String, String> stringStringMap = seaweedFSUtil.uploadFileContent(pdfFilePathServe, splitFileName[0] + ".pdf", FileUtil.readBytes(pdfFilePath));
            } else {
                log.error("PDF 转换失败");
            }
        } else {
            Map<String, String> stringStringMap = seaweedFSUtil.uploadFileContent(pdfFilePathServe, splitFileName[0] + ".pdf", FileUtil.readBytes(pdfFilePath));
        }
    }

    public static void deletePdfFiles(Path folderPath) {
        try {
            Files.walk(folderPath)
                    .filter(path -> path.toString().toLowerCase().endsWith(".pdf"))
                    .forEach(path -> {
                        try {
                            Files.delete(path);
                            log.info("已删除: {}", path);
                        } catch (IOException e) {
                            log.error("删除失败: {}", path);
                        }
                    });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
